package com.syh.jn.scm.domain.upstream.entity.sale;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.domain.AbstractSimpleAggregate;
import com.syh.jn.scm.domain.upstream.entity.logistics.UpLogisticsBill;
import com.syh.jn.scm.domain.upstream.repository.logistics.UpLogisticsBillReadRepository;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.dto.upstream.sale.UpSaleOrderSto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.supplier.logistics.enums.LogisticsBillEnums;
import com.syh.jn.scm.service.api.upstream.logistics.enums.UpLogisticsBillEnum;
import com.syh.jn.scm.service.api.upstream.sale.enums.UpSaleOrderEnums;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.List;

/**
 * 上游销售单聚合
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class UpSaleOrder extends AbstractSimpleAggregate<Long> {
  /**
   * 销售订单编号
   */
  private String code;
  /**
   * 销售订单类型(0：普通采购 1：直采直销 )
   */
  private Short orderType;
  /**
   * 销售订单id(当选择了直采直销时)
   */
  private Long salesOrderId;
  /**
   * 第三方订单号
   */
  private String extCode;
  /**
   * 上游单位的id
   */
  private Long upStreamCompanyId;
  /**
   * 销售订单状态(0：待确认 1：已确认 2：挂起 3：已生成对账单 -1：已取消)
   */
  private Short ordState;
  /**
   * 收货人姓名
   */
  private String deliName;
  /**
   * 收货人联系电话
   */
  private String deliTel;
  /**
   * 要求到货时间
   */
  private Long receiveTimestamp;
  /**
   * 收货地区编码
   */
  private String deliAreaCode;
  /**
   * 收货地址省 市 区
   */
  private String deliArea;
  /**
   * 收货人详细地址
   */
  private String deliAddress;
  /**
   * 发货地区编码
   */
  private String upDeliAreaCode;
  /**
   * 发货地址省 市 区
   */
  private String upDeliArea;
  /**
   * 发货人详细地址
   */
  private String upDeliAddress;
  /**
   * 订单备注
   */
  private String remark;
  /**
   * 优惠金额
   */
  private BigDecimal discount;
  /**
   * 订单总额
   */
  private BigDecimal totalAmount;
  /**
   * 入库总额
   */
  private BigDecimal totalInAmount;
  /**
   * 入库商品总额
   */
  private BigDecimal totalInGoodsAmount;
  //TODO 上游出库总额字段预计以后要删除
  /**
   * 出库总额
   */
  private BigDecimal totalOutAmount;
  //TODO 上游出库商品总额字段预计以后要删除
  /**
   * 出库商品总额
   */
  private BigDecimal totalOutGoodsAmount;
  /**
   * 运费金额
   */
  private BigDecimal totalFreight;
  /**
   * 商品总额
   */
  private BigDecimal goodsTotalAmount;
  /**
   * 录单日期
   */
  private Long inputDateTimestamp;
  /**
   * 发货时间
   */
  private Long deliveryTimestamp;
  /**
   * 入库时间(收货)
   */
  private Long storageTimestamp;
  /**
   * 录单人员id
   */
  private Long operatorId;
  /**
   * 订单账期
   */
  private Integer accountPeriod;
  /**
   * 物流生成状态(0：未生成物流单 1：部分生成物流单2：完成生成物流单)
   */
  private Short generatedState;
  /**
   * 发货状态(0：未发货 1：部分发货 2：完成发货)
   */
  private Short deliveryState;
  /**
   * 签收状态(0：未签收 1：部分签收 2：完成签收)
   */
  private Short collectState;
  /**
   * 对账单id
   */
  private Long statementId;
  /**
   * 我方单据图片
   */
  private String mainSrcImages;
  /**
   * 对方单据图片
   */
  private String secondSrcImages;
  /**
   * 订单明细
   */
  protected List<UpSaleOrderItem> items;

  public UpSaleOrder(UpSaleOrderSto sto) {
    ExtAssert.notNull(sto, "对象为空");
    ValidationUtils.validate(sto);
    ExtBeanUtils.copyProperties(sto, this);
  }

  /**
   * 确认
   */
  public void confirm() {
    if (this.getOrdState().equals(UpSaleOrderEnums.State.STAYCONFIRM.getStatus())) {
      this.ordState = UpSaleOrderEnums.State.CONFIRM.getStatus();
    } else {
      throw new BusinessException("订单不是待确认状态,不能确认订单");
    }
  }

  /**
   * 挂起
   */
  public void handUp() {
    this.ordState = UpSaleOrderEnums.State.HANG.getStatus();
  }

  /**
   * 挂起订单还原待确认
   */
  public void reset() {
    this.ordState = UpSaleOrderEnums.State.STAYCONFIRM.getStatus();
  }

  /**
   * 反确认
   */
  public void stayConfirm() {
    if (!this.getOrdState().equals(UpSaleOrderEnums.State.CONFIRM.getStatus())) {
      throw new BusinessException("订单不是确认状态,不可以反确认订单");
    }
    UpLogisticsBillReadRepository logisticsBillReadRepository = (UpLogisticsBillReadRepository) SpringContextUtils.getBean(UpLogisticsBillReadRepository.class);
    Wrapper we = Wrapper.build().append(Restrictions.eq("orderId", this.id))
            .append(Restrictions.eq("orderType", UpLogisticsBillEnum.ORDER_TYPE_SALE.getStatus()));
    if (logisticsBillReadRepository.getCount(we) > 0) {
      throw new BusinessException("订单已生成物流单,不可以修改");
    }
    if (this.getDeliveryState() != null
            && !this.getDeliveryState().equals(UpSaleOrderEnums.DeliveryState.LOGISTICS_UN_DELIVERY.getStatus())) {
      throw new BusinessException("物流已发车,已收货,不可以反确认订单");
    }
    this.reset();
  }

  /**
   * 取消订单
   */
  public void cancel() {
    if (!this.getOrdState().equals(UpSaleOrderEnums.State.STAYCONFIRM.getStatus())
            && !this.getOrdState().equals(UpSaleOrderEnums.State.CONFIRM.getStatus())) {
      throw new BusinessException("订单不是未确认,确认状态,不可以取消");
    }
    if (this.getDeliveryState() != null
            && !this.getDeliveryState().equals(UpSaleOrderEnums.DeliveryState.LOGISTICS_UN_DELIVERY.getStatus())) {
      throw new BusinessException("物流不是未发车,不可以取消");
    }
    this.ordState = UpSaleOrderEnums.State.CANCEL.getStatus();
  }

  /**
   * 记录已生成物流数量
   *
   * @param logisticsBill
   * @param operate       (1为增加记录，2为减少记录)
   */
  public void countGeneratedQuantity(UpLogisticsBill logisticsBill, int operate) {
    if (operate == 1) {
      logisticsBill.getItems().forEach(logisticsBillItem -> {
        this.items.forEach(orderItem -> {
          if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
            orderItem.setGeneratedQuantity(orderItem.getGeneratedQuantity() == null ? logisticsBillItem.getQuantity() :
                    orderItem.getGeneratedQuantity().add(logisticsBillItem.getQuantity()));
          }
        });
      });
    } else {
      logisticsBill.getItems().forEach(logisticsBillItem -> {
        this.items.forEach(orderItem -> {
          if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
            orderItem.setGeneratedQuantity(orderItem.getGeneratedQuantity().subtract(logisticsBillItem.getQuantity()));
          }
        });
      });
    }

    //默认为已完全生成物流单
    this.generatedState = UpSaleOrderEnums.GeneratedState.LOGISTICS_WHOLE_GENERATE.getStatus();
    //默认标记为未生成物流单
    boolean unGenerated = true;

    for (UpSaleOrderItem item : this.items) {
      //订单项已生成数量小于订单数量则为部分生成物流单
      if (this.generatedState.equals(UpSaleOrderEnums.GeneratedState.LOGISTICS_WHOLE_GENERATE.getStatus())
              && item.getGeneratedQuantity().compareTo(item.getQuantity()) < 0) {
        this.generatedState = UpSaleOrderEnums.GeneratedState.LOGISTICS_PART_GENERATE.getStatus();
      }
      //订单项已发货数量大于0 则不是未发货
      if (unGenerated && item.getGeneratedQuantity().compareTo(BigDecimal.ZERO) > 0) {
        unGenerated = false;
      }
    }
    if (unGenerated) {
      this.generatedState = UpSaleOrderEnums.GeneratedState.LOGISTICS_UN_GENERATE.getStatus();
    }
  }

  /**
   * 发货信息更新
   */
  public void delivery(UpLogisticsBill bill) {
    if (this.deliveryState.equals(UpSaleOrderEnums.DeliveryState.LOGISTICS_WHOLE_DELIVEED.getStatus()))
      throw new BusinessException("发货失败，已全部发货！");
    //修改订单项发货数量
    bill.getItems().forEach(logisticsBillItem -> {
      this.items.forEach(orderItem -> {
        if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
          orderItem.setOutedQuantity(orderItem.getOutedQuantity() == null ? logisticsBillItem.getQuantity() :
                  orderItem.getOutedQuantity().add(logisticsBillItem.getQuantity()));
        }
      });
    });
    this.deliveryTimestamp = System.currentTimeMillis();
    this.calculateTotalOutAmount();
    this.calculateDeliveryStatus();
  }

  /**
   * 取消发货信息更新
   */
  public void cancelDelivery(UpLogisticsBill bill) {
    if (this.deliveryState.equals(UpSaleOrderEnums.DeliveryState.LOGISTICS_UN_DELIVERY.getStatus()))
      throw new BusinessException("取消发货失败，无发货记录！");
    //修改订单项发货数量
    bill.getItems().forEach(logisticsBillItem -> {
      this.items.forEach(orderItem -> {
        if (orderItem.getId().equals(logisticsBillItem.getOrderItemId())) {
          orderItem.setOutedQuantity(orderItem.getOutedQuantity().subtract(logisticsBillItem.getQuantity()));
        }
      });
    });
    this.calculateTotalOutAmount();
    this.calculateDeliveryStatus();
  }

  //计算订单发货总额、商品发货总额
  private void calculateTotalOutAmount() {
    //计算订单已出库商品总额
    BigDecimal totalAmount = BigDecimal.ZERO;
    for (UpSaleOrderItem item : this.items) {
      totalAmount = totalAmount.add(item.calculateTotalOutAmount());
    }
    this.totalOutGoodsAmount = totalAmount;

    //先计算出该订单下已发出、已签收状态的物流单据的物流费用
    UpLogisticsBillReadRepository logisticsBillReadRepository = (UpLogisticsBillReadRepository) SpringContextUtils.getBean(UpLogisticsBillReadRepository.class);
    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("orderId", this.id));
    we.append(Restrictions.eq("orderType", UpLogisticsBillEnum.ORDER_TYPE_SALE.getStatus()));
    we.append(Restrictions.or(Restrictions.eq("logisticsState", UpLogisticsBillEnum.DRIVER_DELIVEED.getStatus()),
            Restrictions.eq("logisticsState", UpLogisticsBillEnum.DRIVER_SIGNIN.getStatus())));
    List<UpLogisticsBill> logisticsBills = logisticsBillReadRepository.getList(we);

    BigDecimal logisticsBillBeforeBuyFreight = BigDecimal.ZERO;//物流单据为预收买家的所有物流费用
    for (UpLogisticsBill logisticsBill : logisticsBills) {
      if (logisticsBill.getFreightTake() != null && logisticsBill.getFreightTake().equals(LogisticsBillEnums.FreightTake.BUY.getStatus())
              && logisticsBill.getFreightType().equals(LogisticsBillEnums.FreightType.BEFORE.getStatus()))
        logisticsBillBeforeBuyFreight = logisticsBillBeforeBuyFreight.add(logisticsBill.getTotalFreight());
    }

    //减去优惠金额
    if (this.discount != null) {
      totalAmount = totalAmount.subtract(this.discount);
    }
    //加上预收买家的运费金额
    totalAmount = totalAmount.add(logisticsBillBeforeBuyFreight);
    this.totalFreight = logisticsBillBeforeBuyFreight;
    this.totalOutAmount = totalAmount.compareTo(BigDecimal.ZERO) < 1 ? BigDecimal.ZERO : totalAmount;
    this.lastUpdateTimeStamp = System.currentTimeMillis();
  }


  //计算订单发货状态
  private void calculateDeliveryStatus() {
    this.deliveryState = UpSaleOrderEnums.DeliveryState.LOGISTICS_WHOLE_DELIVEED.getStatus();
    //默认标记为未发货
    boolean unDelivery = true;

    //计算订单已出库商品总额
    for (UpSaleOrderItem item : this.items) {
      //订单项已发货数量小于订单数量则为部分发货
      if (this.deliveryState.equals(UpSaleOrderEnums.DeliveryState.LOGISTICS_WHOLE_DELIVEED.getStatus())
              && item.getOutedQuantity().compareTo(item.getQuantity()) < 0) {
        this.deliveryState = UpSaleOrderEnums.DeliveryState.LOGISTICS_PART_DELIVEED.getStatus();
      }
      //订单项已发货数量大于0 则不是未发货
      if (unDelivery && item.getOutedQuantity().compareTo(BigDecimal.ZERO) > 0) {
        unDelivery = false;
      }
    }
    if (unDelivery) {
      this.deliveryState = UpSaleOrderEnums.DeliveryState.LOGISTICS_UN_DELIVERY.getStatus();
      this.deliveryTimestamp = null;
    }
  }

  /**
   * 生成对账单
   */
  public void generating(Long statementOfAccountId) {
    if (this.collectState.equals(UpSaleOrderEnums.CollectState.LOGISTICS_UN_COLLECT.getStatus())) {
      throw new BusinessException("销售单" + this.code + "未签收，无法生成对账单");
    }
    if (this.ordState.equals(UpSaleOrderEnums.State.STATEMENT.getStatus())) {
      throw new BusinessException("销售单已生成对账单!");
    }
    this.statementId = statementOfAccountId;
    this.ordState = UpSaleOrderEnums.State.STATEMENT.getStatus();
  }

  /**
   * 取消对账单
   */
  public void cancelGenerating() {
    if (!this.ordState.equals(UpSaleOrderEnums.State.STATEMENT.getStatus())) {
      throw new BusinessException("销售单已取消对账单!");
    }
    this.statementId = null;
    this.ordState = UpSaleOrderEnums.State.CONFIRM.getStatus();
  }

  /**
   * 下游采购订单上传图片
   *
   * @param dto
   */
  public void upload(FilesDto dto) {
    this.secondSrcImages = dto.getFiles();
  }
}
